/**
 * #info
 *
 * @author Vinsea(liwentao@thunisoft.com)
 * @createTime 2019/02/21
 * @updateTime   2019/02/25
 * @description module component
 */
import config from '../../../config/config.js'
// plugin
import { on, off } from '../../../utils/dom'
// components
import Icon from '../../basic/icon/index.vue'
import Spin from '../../tools/spin/spin/index.vue'

// prefix
const prefixCls = config.prefix + '-captcha-slide'

/**
 * #item
 *
 * @type aty-captcha-slide
 * @cn 滑动验证
 * @order 1
 * @menu 验证码
 * @stPlugin true
 */
const module = {
  name: prefixCls,
  components: { Icon, Spin },
  data () {
    return {
      // timer: '',
      height: 150,
      visible: false, // 是否显示验证图
      spinShow: false, // 加载中遮罩
      targetImage: '', // 验证图 - 底图
      templateImage: '', // 验证图 - 拼图模板
      templateImageTop: 0, // 拼图模板图片距顶部的距离
      currentX: 0, // 位移量
      startX: 0, // 开始拖拽起始位置
      isMouseDown: false, // 鼠标按下
      dragging: true, // 拖拽中
      verifySuccess: false, // 图片验证成功
      verifyFail: false, // 图片验证失败
      loadVerifyImgFail: true, // 加载验证图失败
      isShowFailText: false, // 显示失败提示文字
      sliderWrapperHeight: 30,
      scale: 1, // 底图的原图和用户自定义的宽度缩放比
      msg: ''
    }
  },
  props: {

    /**
     * #property
     *
     * @name      trigger
     * @cn        触发方式
     * @type      list
     * @options    [normal,hover]
     * @value      normal
     * @description   触发方式，取值为[normal,hover]中的一个
     */
    trigger: {
      validator (value) {
        return Artery.isOneOf(value, ['normal', 'hover'])
      },
      default: 'normal'
    },
    /**
     * #property
     *
     * @name    width
     * @cn      容器/图片宽度
     * @type    number
     * @bind    must
     * @value  300
     * @description 容器/图片宽度
     */
    width: {
      type: Number,
      default: 300
    },
    /**
     * #property
     *
     * @name      sliderText
     * @cn        滑块区域的提示文字
     * @type      string
     * @value     拖动滑块完成拼图
     * @description   滑块区域的提示文字
     */
    sliderText: {
      type: String,
      default: '拖动滑块完成拼图'
    },
    /**
     * #property
     *
     * @name      successText
     * @cn        验证成功的提示文字
     * @type      string
     * @value     验证成功！
     * @description   验证成功的提示文字
     */
    successText: {
      type: String,
      default: '验证成功！'
    },
    /**
     * #property
     *
     * @name      failText
     * @cn        验证失败的提示文字
     * @type      string
     * @value     验证失败！请将拼图拖动至正确的位置！
     * @description   验证失败的提示文字
     */
    failText: {
      type: String,
      default: '验证失败！请将拼图拖动至正确的位置！'
    },
    /**
     * #property
     *
     * @name    imgDataUrl
     * @cn      图片数据的url
     * @group   url
     * @type    string
     * @value   artery/webSecurity/captcha/slide
     * @description GET请求，获取底图和目标模版图相关信息，参数是宽度
     */
    imgDataUrl: {
      type: String,
      default: 'artery/webSecurity/captcha/slide'
    },
    /**
     * #property
     *
     * @name    verifyUrl
     * @cn      验证结果的url
     * @group   url
     * @type    string
     * @value   artery/webSecurity/captcha/slide/validate/
     * @description GET请求，验证结果是否正确,参数是位移值
     */
    verifyUrl: {
      type: String,
      default: 'artery/webSecurity/captcha/slide/validate/'
    }

  },
  computed: {
    // 最外层容器class
    wrapperClasses () {
      return [
        `${prefixCls}-wrapper`,
        `${prefixCls}-wrapper-${this.trigger}`,
        {
          [`${prefixCls}-load-fail`]: this.loadVerifyImgFail // 获取验证图片失败
        }
      ]
    },
    styles () {
      const heightTmp = this.trigger === 'normal' ? this.height + this.sliderWrapperHeight + 10 : this.sliderWrapperHeight
      return {
        width: this.width + 'px',
        height: heightTmp + 'px'
      }
    },
    // 滑块所在容器class
    classes () {
      return [
        `${prefixCls}-slider-wrapper`,
        {
          [`${prefixCls}-success`]: this.verifySuccess, // 验证成功
          [`${prefixCls}-fail`]: this.verifyFail // 验证失败
        }
      ]
    },
    // 验证图容器class
    imgWrapperClass () {
      return [
        `${prefixCls}-img-wrapper`,
        {
          [`${prefixCls}-img-wrapper-show`]: this.visible
        }
      ]
    },
    // 验证失败后的按钮class
    failBtnClasses () {
      return [`${prefixCls}-btn`,
        {
          [`${prefixCls}-fail-btn`]: this.verifyFail
        }
      ]
    },
    sliderTextClass () {
      return `${prefixCls}-text`
    },
    sliderPassClass () {
      return `${prefixCls}-pass`
    },
    imgTargetClass () {
      return `${prefixCls}-img`
    },
    imgTmpClass () {
      return `${prefixCls}-tmp`
    },
    iconRefreshClass () {
      return `${prefixCls}-img-refresh`
    },
    iconLoadingClass () {
      return `${prefixCls}-spin-icon-load`
    },
    resultErrorClass () {
      return `${prefixCls}-img-result`
    },
    resultTipClass () {
      return [
        `${prefixCls}-tip`,
        {
          [`${prefixCls}-tip-show`]: this.verifySuccess || this.isShowFailText, // 验证完显示
          [`${prefixCls}-tip-fail`]: this.isShowFailText, // 验证失败
          [`${prefixCls}-tip-success`]: this.verifySuccess // 验证成功
        }
      ]
    },
    resultTipText () {
      return this.isShowFailText ? this.failText : this.successText
    },
    imgTmpWidth () {
      return Math.round(60 * this.scale)
    },
    imgTmpHeight () {
      return Math.round(60 * (this.height / 150))
    }
  },
  methods: {

    // 获取当前X轴坐标，区分鼠标和移动端
    getPointerX (e) {
      return e.type.indexOf('touch') !== -1 ? Math.round(e.touches[0].clientX) : Math.round(e.clientX)
    },

    handleMouseenter () {
      if (this.timer) {
        clearTimeout(this.timer)
      }
      this.timer = setTimeout(() => {
        this.visible = true
      }, 50)
    },

    handleMouseleave () {
      if (this.timer) {
        clearTimeout(this.timer)
      }
      this.timer = setTimeout(() => {
        this.visible = false
      }, 100)
    },

    onPointerDown (event) {
      if (this.verifySuccess || this.spinShow) {
        return
      }
      this.isMouseDown = true
      event.preventDefault()
      this.startX = this.getPointerX(event)
      on(window, 'mousemove', this.onPointerDrag)
      on(window, 'touchmove', this.onPointerDrag)
      on(window, 'mouseup', this.onPointerDragEnd)
      on(window, 'touchend', this.onPointerDragEnd)
      /**
       * #event
       *
       * @name drag-start
       * @cn 鼠标按下事件
       * @param startX 起始位置
       * @body console.log('鼠标按下')
       * @description 对滑块鼠标按下时的方法
       */
      this.$emit('drag-start', this.startX)
    },

    onPointerDrag (event) {
      this.dragging = true
      const diff = this.getPointerX(event) - this.startX
      if (diff > 0 && diff < (this.width - this.imgTmpWidth)) {
        this.currentX = diff
      }

      /**
       * #event
       *
       * @name dragging
       * @cn 鼠标拖动事件
       * @param currentX 当前位置
       * @body console.log('鼠标正在移动...')
       * @description 对滑块鼠拖动时的方法
       */
      this.$emit('dragging', this.currentX)
    },

    onPointerDragEnd () {
      this.isMouseDown = this.dragging = false
      this.requestResult()
      off(window, 'mousemove', this.onPointerDrag)
      off(window, 'touchmove', this.onPointerDrag)
      off(window, 'mouseup', this.onPointerDragEnd)
      off(window, 'touchend', this.onPointerDragEnd)
      /**
       * #event
       *
       * @name drag-end
       * @cn 鼠标弹起事件
       * @body console.log('鼠标弹起')
       * @description  mouseup时的方法
       */
      this.$emit('drag-end')
    },

    // 重置
    reset () {
      this.dragging = true
      this.spinShow = true
      this.currentX = 0
      this.startX = 0
      this.verifyFail = false
      this.verifySuccess = false
    },

    // 请求验证图
    requestVerifyImg () {
      this.reset()
      const params = {}
      if (this.width !== 300) {
        params.width = this.width
      }
      const uri = `${this.imgDataUrl}?time=${new Date().getTime()}`
      Artery.ajax.get(uri, { params }).then((result) => {
        this.spinShow = false
        this.handleImgResult(result)
      }).catch((result) => {
        this.msg = (result && result.msg) ? result.msg : '加载失败，请点击右上角刷新重试！'
        this.targetImage = ''
        this.templateImage = ''
        this.templateImageTop = 0
        this.loadVerifyImgFail = true
        this.spinShow = false
      })
    },

    // 处理请求结果
    handleImgResult (result) {
      this.targetImage = 'data:img/jpg;base64,' + result.targetImage
      this.templateImage = 'data:img/jpg;base64,' + result.templateImage
      this.templateImageTop = result.top - 1
      this.scale = result.scale
      this.loadVerifyImgFail = false
    },

    // 验证
    requestResult () {
      Artery.ajax.get(this.verifyUrl + this.currentX).then((result) => {
        /**
         * #event
         *
         * @name on-success
         * @cn 验证结果
         * @body console.log('验证成功')
         * @description 验证成功事件
         */
        this.$emit('on-success')
        this.verifySuccess = true
      }).catch(() => {
        /**
         * #event
         *
         * @name on-failure
         * @cn 验证失败
         * @body console.log('验证失败')
         * @description 验证失败事件
         */
        this.$emit('on-failure')
        this.handleFail()
        this.toggleVerifyFail()
      })
    },

    // 处理验证失败结果
    handleFail () {
      // 显示失败提示
      this.isShowFailText = true
      const t = setTimeout(() => {
        this.isShowFailText = false
        clearTimeout(t)
      }, 1500)
      // 失败重新验证 加定时是为了凸显交互
      const requestImg = setTimeout(() => {
        this.requestVerifyImg()
        clearTimeout(requestImg)
      }, 700)
    },

    // 失败后动画提示,提出方法供使用者通过ref调用
    toggleVerifyFail () {
      this.verifyFail = true
      const t = setTimeout(() => {
        this.verifyFail = false
        clearTimeout(t)
      }, 600)
    }
  },
  created () {
    this.visible = this.trigger === 'normal'
    this.height = 150 * (this.width / 300)
    this.reset()
  },
  beforeMount () {
    this.requestVerifyImg()
  },
  mounted () {
    this.sliderWrapperHeight = this.$refs.slider.offsetHeight
  }
}
export default module
